#include "Connection.h"

Connection::Connection()
{
	Login.SetConnection(this);
	Cashier.SetConnection(this);
	LoginID = Login.GetModuleID();
	CashierID = Cashier.GetModuleID();
}

Connection::~Connection() // should only be called by NetworkSystem
{
	State = STATE_CLOSING;
	while (PendingWrite || PendingRead)
	{
		boost::this_thread::sleep(5);
	};
}

void Connection::OnRead(const boost::system::error_code& err) // already read the header
{
	boost::recursive_mutex::scoped_lock _lock(ReadMutex);
	PendingRead--;
	if (State != STATE_RUNNING)
	{
		ReadBuffer.Reset();
		return;
	}
	// Do event reading and firing here
	PendingRead++;
	boost::asio::async_read(Socket, boost::asio::buffer(ReadBuffer.GetBuffer(), NetworkMessage::HeaderSize), boost::bind(&Connection::ParseHeader, this, boost::asio::placeholders::error)); // so lets do it again
}

void Connection::ParseHeader(const boost::system::error_code& err)
{
	boost::recursive_mutex::scoped_lock _lock(ReadMutex);
	PendingRead--;
	if (State != STATE_RUNNING)
	{
		return;
	}
	PendingRead++;
	boost::asio::async_read(Socket, boost::asio::buffer(ReadBuffer.GetBuffer(), NetworkMessage::HeaderSize), boost::bind(&Connection::OnRead, this, boost::asio::placeholders::error));
	// Setup to read the message body
}

void Connection::OnWrite(const boost::system::error_code& err)
{
	boost::recursive_mutex::scoped_lock _lock(WriteMutex);
	PendingWrite--;
	if (State != STATE_RUNNING)
	{
		PendingWrite = 0;
		WriteBuffer.Reset();
		return;
	}
	InternalSend();
}

void Connection::OnAccept()
{
	boost::recursive_mutex::scoped_lock _lock(ReadMutex);
	if (State != STATE_RUNNING)
	{
		return;
	}
	PendingRead++;
	boost::asio::async_read(Socket, boost::asio::buffer(ReadBuffer.GetBuffer(), NetworkMessage::HeaderSize), boost::bind(&Connection::ParseHeader, this, boost::asio::placeholders::error));
}

void Connection::Send(NetworkMessage* msg)
{
	boost::recursive_mutex::scoped_lock _lock(WriteMutex);
	if (State != STATE_RUNNING)
	{
		return;
	}
	NetworkMessage* message;
	message = new NetworkMessage(&msg);
	PendingOutput.push_back(message);
	if (PendingWrite == 0) // Nothing pending ATM
	{
		InternalSend();
	}
}

void Connection::InternalSend()
{
	std::list<NetworkMessage*>::iterator it = PendingOutput.begin();
	if (it == PendingOutput.end())
	{
		return;
	}
	WriteBuffer.Copy(*it);
	PendingOutput.erase(it);
	PendingWrite++;
	boost::asio::async_write(Socket, boost::asio::buffer(WriteBuffer.GetBuffer(), WriteBuffer.GetLength()), boost::bind(&Connection::OnWrite, this, boost::asio::placeholders::error));
}
